package com.sensetime.bi.senselink.server.parse;

import com.sensetime.bi.senselink.server.constant.PacketConstant;
import com.sensetime.bi.senselink.server.entity.RtspRequestMsg;
import com.sensetime.bi.senselink.server.entity.RtspResponsetMsg;
import com.sensetime.bi.senselink.server.entity.rtp.TcpHeader;
import com.sensetime.bi.senselink.server.entity.rtp.TcpRtpPacket;
import com.sensetime.bi.senselink.server.util.ByteBufUtil;
import com.sensetime.bi.senselink.server.util.StringUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
public class PackageDecoder extends ByteToMessageDecoder {
    /**
     * <pre>
     * 包类型如果为：
     * 1. TCP RTP包, 则至少需要头长度为 4字节的内容，才能完成拆包
     * 2. 如果为RTSP包， 数据包大小肯定大于4自己
     * </pre>
     */
    public final int BASE_LENGTH = 4;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception {
        Channel channel = ctx.channel();
            log.debug("=========================== 1 receive message ================= id:" + channel.id() + ": " + channel.remoteAddress() + " -> " + channel.localAddress());
            // 可读长度必须大于基本长度
            if (byteBuf.readableBytes() >= BASE_LENGTH) {
                byte aByte = byteBuf.getByte(byteBuf.readerIndex());
                log.debug("magic number:[{}]", StringUtils.byteToHex(aByte));
                if (aByte == PacketConstant.RTP) { // RTP
                    while (byteBuf.readableBytes() >= BASE_LENGTH) {
                        // 记录包头开始的index
                        int beginReader = byteBuf.readerIndex();
                        // 读取4个字节
                        ByteBuf buf = byteBuf.readBytes(4);
                        TcpHeader tcpHeader = new TcpHeader();
                        tcpHeader.setHeader(buf);
                        boolean destroyed = buf.release();
                        assert !destroyed;
                        assert buf.refCnt() == 0;
                        log.debug(tcpHeader.print());

                        // 判断请求数据包数据是否到齐
                        if (tcpHeader.rtpPkgLength > byteBuf.readableBytes()) {
                            // 还原读指针
                            byteBuf.readerIndex(beginReader);
                            log.debug("=========== rtp : 等待数据包到齐 =====================");
                            return;
                        }
                        // 读取rtp package
                        ByteBuf rtpBuf = byteBuf.readBytes(tcpHeader.rtpPkgLength);
                        byte[] bytes = new byte[tcpHeader.rtpPkgLength];
                        rtpBuf.getBytes(rtpBuf.readerIndex(), bytes);
                        rtpBuf.release();

                        TcpRtpPacket tcpRtpPacket = new TcpRtpPacket();
                        tcpRtpPacket.tcpHeader = tcpHeader;
                        tcpRtpPacket.rtpBytes = bytes;
                        list.add(tcpRtpPacket);
                    }
                } else {
                    // RTSP 消息拆包
                    // 记录包头开始的index
                    int beginReader = byteBuf.readerIndex();

                    // Header 信息解析
                    int totalLen = byteBuf.readableBytes();
                    ByteBuf buf = byteBuf.readBytes(totalLen);
                    int posByCRLF = ByteBufUtil.getPosByCRLF(buf);
                    if (posByCRLF == 0) {
                        String msgStr = ByteBufUtil.convertByteBufToString(buf);
                        log.error("=========== rtsp 包数据没有发现结束符，等待数据包到齐! =====================[{}]", StringUtils.bytesToHex(msgStr.getBytes(), msgStr.getBytes().length));
                        // 还原读指针
                        byteBuf.readerIndex(beginReader);
                        return;
                    } else if (posByCRLF < totalLen-1){
                        // 还原读指针
                        byteBuf.readerIndex(beginReader + posByCRLF + 1);
                    }
                    ByteBuf headBuf = buf.readBytes(posByCRLF+1);
                    buf.release();
                    String headStr = ByteBufUtil.convertByteBufToString(headBuf);
                    headBuf.release();

                    if (headStr.substring(0, 5).toLowerCase().startsWith("rtsp")) {
                        log.debug("Received RTSP response message , start to decode ...., response:\n" + headStr);
                        RtspResponsetMsg rtspResponsetMsg = new RtspResponsetMsg(headStr);
                        log.debug("rtsp response content-length:{}", rtspResponsetMsg.getContentLength());
                        if (rtspResponsetMsg.getContentLength() > 0 && rtspResponsetMsg.getContentLength() > byteBuf.readableBytes()) {
                            log.info("=========== rtsp : 等待数据包到齐 =====================");
                            // 还原读指针
                            byteBuf.readerIndex(beginReader);
                            return;
                        }
                        if (rtspResponsetMsg.getContentLength() > 0) {
                            ByteBuf contentBuf = byteBuf.readBytes(rtspResponsetMsg.getContentLength());
                            String bodyStr = ByteBufUtil.convertByteBufToString(contentBuf);
                            contentBuf.release();
                            rtspResponsetMsg.addContent(bodyStr);
                        }
                        list.add(rtspResponsetMsg);
                    } else {
                        // RTSP Request message TCP拆包
                        log.debug("Received RTSP request message , start to decode ....:\n" + headStr);
                        RtspRequestMsg rtspRequestMsg = new RtspRequestMsg(headStr);
                        log.debug("rtsp request content-length:{}", rtspRequestMsg.getContentLength());
                        if (rtspRequestMsg.getContentLength() > 0 && rtspRequestMsg.getContentLength() > byteBuf.readableBytes()) {
                            log.info("=========== rtsp : 等待数据包到齐 =====================");
                            // 还原读指针
                            byteBuf.readerIndex(beginReader);
                            return;
                        }
                        if (rtspRequestMsg.getContentLength() > 0) {
                            ByteBuf contentBuf = byteBuf.readBytes(rtspRequestMsg.getContentLength());
                            String bodyStr = ByteBufUtil.convertByteBufToString(contentBuf);
                            contentBuf.release();
                            rtspRequestMsg.addContent(bodyStr);
                        }
                        list.add(rtspRequestMsg);
                    }
                }
            }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("错误信息:{}", cause.getMessage());
        super.exceptionCaught(ctx, cause);
    }
}
